package han.chensing.latos.common.level.content.timeLine.events;

import han.chensing.latos.common.file.annotation.CirnoFindParent;
import han.chensing.latos.common.level.content.timeLine.frame.FrameGeneral;
import han.chensing.latos.common.level.content.timeLine.frame.GeneralEventTypes;
import han.chensing.latos.common.level.content.timeLine.motion.ValueMotion;

import java.io.Serial;
import java.io.Serializable;
import java.lang.reflect.Method;

@CirnoFindParent
public class TimeLineMotionEvent extends TimeLineEvent<FrameGeneral> implements Serializable {
    @Serial
    private static final long serialVersionUID = -5858710662218773792L;

    private ValueMotion valueMotion;

    public static TimeLineMotionEvent wrapEvent(FrameGeneral[] sideFrames, ValueMotion valueMotion){
        TimeLineMotionEvent timeLineMotionEvent =new TimeLineMotionEvent();
        timeLineMotionEvent.setValueMotion(valueMotion);
        timeLineMotionEvent.setFromTime(sideFrames[0].getTime());
        timeLineMotionEvent.setToTime(sideFrames[1].getTime());
        return timeLineMotionEvent;
    }

    @Override
    public FrameGeneral getFrame(float relativeTime) {
        FrameGeneral frame=new FrameGeneral();
        try {
            ValueMotion valueMotion = getValueMotion();
            GeneralEventTypes type = valueMotion.getType();
            frame.addTypes(type);
            float from = valueMotion.getStartValue();
            float to=valueMotion.getValue(relativeTime);
            invokeSetterMethodByType(type, frame, from+to);
        }catch (Exception e){
            e.printStackTrace();
        }
        return frame;
    }

    public Float getValueByTypeOfFrame(FrameGeneral frame) throws Exception {
        GeneralEventTypes generalEventTypes = valueMotion.getType();
        Class<FrameGeneral> frameClass = FrameGeneral.class;
        Method[] methods = frameClass.getMethods();
        for (Method method : methods) {
            String methodName = method.getName();
            if (!(methodName.contains("get")&&methodName.contains(generalEventTypes.name()))) continue;
            return (float) method.invoke(frame);
        }
        return null;
    }

    private void invokeSetterMethodByType(GeneralEventTypes generalEventTypes, FrameGeneral frame, float value) throws Exception{
        Class<FrameGeneral> frameClass = FrameGeneral.class;
        Method[] methods = frameClass.getMethods();
        for (Method method : methods) {
            String methodName = method.getName();
            if (!(methodName.contains("set")&&methodName.contains(generalEventTypes.name()))) continue;
            method.invoke(frame,value);
            break;
        }
    }

    public ValueMotion getValueMotion() {
        return valueMotion;
    }

    public void setValueMotion(ValueMotion valueMotion) {
        this.valueMotion = valueMotion;
    }
}
